<template>
  <div>
    <div
      class="container"
      ref="container"
      @mousedown="containerMousedown"
      @mousemove="containerMousemove"
      @mouseup="containerMouseup"
    >
      <div
        :style="{
          top: Math.floor(item.index / 4) * 50 + 'px',
          left: item.index % 4 * 50 + 'px',
        }"
        v-for="(item, index) in data" :key="index"
        class="content"
      >
        <!--      <div class="col" v-for="(ch_item, ch_index) in item" :key="ch_index">-->
        <div>
          <span style="color: red">{{item.val ? item.val : ''}}</span>
<!--          {{item}}-->
        </div>
        <!--      </div>-->
      </div>
    </div>
    <div @click="generate(checkRoom())">按钮</div>
  </div>
</template>

<script lang="ts">
import { ref, defineComponent, onMounted } from 'vue'

const directionMap = {
  left: 'left',
  right: 'right',
  up: 'up',
  down: 'down'
}

interface DirectionIndexType {
  [left: string]: Array<Array<number>>;
  right: Array<Array<number>>;
  up: Array<Array<number>>;
  down: Array<Array<number>>;
}

interface DataType {
 val: number;
 index: number;
 orgIndex?: number;
 del?: number;
}

interface TempDataType {
  [num: number]: DataType;
}

const directionIndex: DirectionIndexType = {
  left: [
    [3, 2, 1, 0],
    [7, 6, 5, 4],
    [11, 10, 9, 8],
    [15, 14, 13, 12]
  ],
  right: [
    [0, 1, 2, 3],
    [4, 5, 6, 7],
    [8, 9, 10, 11],
    [12, 13, 14, 15]
  ],
  up: [
    [15, 11, 7, 3],
    [14, 10, 6, 2],
    [13, 9, 5, 1],
    [12, 8, 4, 0]
  ],
  down: [
    [0, 4, 8, 12],
    [1, 5, 9, 13],
    [2, 6, 10, 14],
    [3, 7, 11, 15]
  ]
}

export default defineComponent({
  name: '2048_1',
  setup () {
    const data = ref<Array<DataType>>([
      { val: 0, index: 0 }, { val: 0, index: 1 }, { val: 0, index: 2 }, { val: 0, index: 3 },
      { val: 0, index: 4 }, { val: 0, index: 5 }, { val: 0, index: 6 }, { val: 0, index: 7 },
      { val: 0, index: 8 }, { val: 0, index: 9 }, { val: 0, index: 10 }, { val: 0, index: 11 },
      { val: 0, index: 12 }, { val: 0, index: 13 }, { val: 0, index: 14 }, { val: 0, index: 15 }
    ])
    const baseInfo = [2, 4]
    let clientX: number | null = null
    let clientY: number | null = null
    let flag = false
    let count = 0
    const checkRoom = () => {
      const arr = []
      for (let n = 0; data.value.length > n; n++) {
        if (!data.value[n].val) {
          arr.push(n)
        }
      }
      return arr
    }

    const generate = (arr: Array<number>) => {
      const num = baseInfo[Math.floor(baseInfo.length * Math.random())]
      const index = arr[Math.floor(arr.length * Math.random())]
      data.value[index].val = num
    }

    const containerMousedown = (e: MouseEvent) => {
      flag = true
      clientX = e.clientX
      clientY = e.clientY
    }

    const containerMousemove = (e: MouseEvent) => {
      if (flag) {
        count++
        if (count < 3) {
          return
        }
        count = 0
        const x = e.clientX - (clientX as number)
        const y = (clientY as number) - e.clientY
        let direction: string | null = null
        if (!x && !y) {
          return
        }
        flag = false
        if (!x) {
          direction = y > 0 ? directionMap.up : directionMap.down
        } else if (!y) {
          direction = x > 0 ? directionMap.right : directionMap.left
        } else if (x > 0 && y > 0) {
          direction = Math.abs(x / y) > 1 ? directionMap.right : directionMap.up
        } else if (x > 0 && y < 0) {
          direction = Math.abs(x / y) > 1 ? directionMap.right : directionMap.down
        } else if (x < 0 && y > 0) {
          direction = Math.abs(x / y) > 1 ? directionMap.left : directionMap.up
        } else if (x < 0 && y < 0) {
          direction = Math.abs(x / y) > 1 ? directionMap.left : directionMap.down
        }
        // const copyData: Array<number> = [...data.value]
        const tempArr: Array<Array<DataType>> = [[], [], [], []]
        const tempIndex = directionIndex[direction as string]
        const dataMap: TempDataType = {}
        data.value.map(item => {
          dataMap[item.index as number] = item
        })
        console.info(dataMap)
        // 通过方向获取有数字的格子
        for (let i = 0; tempIndex.length > i; i++) {
          for (let n = 0; tempIndex[i].length > n; n++) {
            if (dataMap[tempIndex[i][n]] && dataMap[tempIndex[i][n]].val) {
              tempArr[i].push({
                val: dataMap[tempIndex[i][n]].val,
                index: tempIndex[i][n],
                orgIndex: tempIndex[i][n]
              })
            }
          }
        }
        // 以滑动方向相反的顺序 相同的数字相加合并
        for (let i = 0; tempArr.length > i; i++) {
          const item = tempArr[i]
          for (let n = 0; item.length > n && item.length > 1; n++) {
            if (item[item.length - n - 2] && item[item.length - n - 1].val === item[item.length - n - 2].val && !item[item.length - n - 2].del) {
              item[item.length - n - 2].del = 2
              item[item.length - n - 2].index = item[item.length - n - 1].index
              item[item.length - n - 1].val *= 2
              item[item.length - n - 1].del = 1
            }
          }
          // 补0
          while (tempArr[i].length < 4) {
            tempArr[i].unshift({ val: 0, index: -1 })
          }
        }
        // 移动后的格子的位置
        for (let i = 0; tempArr.length > i; i++) {
          for (let n = 0; tempArr[i].length > n; n++) {
            if (tempArr[i][n].del !== 2) {
              tempArr[i][n].index = tempIndex[i][n]
            }
          }
        }
        // let isChange = false
        for (let i = 0; tempArr.length > i; i++) {
          for (let n = 0; tempArr[i].length > n; n++) {
            if (tempArr[i][n].orgIndex !== undefined) {
              let newIndex: number|null = null
              let orgIndex: number|null = null
              data.value.map((item, index) => {
                if (tempArr[i][n].index === item.index) {
                  orgIndex = index
                }
                if (tempArr[i][n].orgIndex === item.index) {
                  newIndex = index
                }
                return item
              })
              if (orgIndex !== null && newIndex !== null) {
                if (tempArr[i][n].del) {
                  data.value[newIndex as number].del = tempArr[i][n].del
                }
                data.value[orgIndex as number].index = tempArr[i][n].orgIndex as number
                data.value[newIndex as number].index = tempArr[i][n].index
                setTimeout(() => {
                  data.value[newIndex as number].val = tempArr[i][n].val
                }, 300)
              }
            }
          }
        }
        const checkRoomResult = checkRoom()
        if (!checkRoomResult.length) {
          console.info('结束')
          return
        }
        // if (isChange) {
        //   generate(checkRoomResult)
        // }
        console.info(x, y, direction, tempArr, data.value)
      }
    }

    const containerMouseup = () => {
      flag = false
    }

    onMounted(() => {
      generate(checkRoom())
    })
    return {
      data,
      generate,
      checkRoom,
      containerMousedown,
      containerMousemove,
      containerMouseup
    }
  }
})
</script>

<style scoped lang="less">
  .container {
    width: 200px;
    height: 200px;
    border: 1px solid #e0e0e0;
    border-radius: 3px;
    display: flex;
    flex-wrap: wrap;
    user-select: none;
    position: relative;
    .content {
      width: 25%;
      height: 25%;
      box-sizing: border-box;
      position: absolute;
      transition: all 0.3s;
      & > div {
        transition: all .3s;
        box-sizing: border-box;
        width: 100%;
        height: 100%;
        border: 3px solid #42b983;
        display: flex;
        align-items: center;
        justify-content: center;
      }
    }
  }
</style>
